package com.gltqe.cipher;


import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.lang.reflect.Field;

/**
 * 自定义 Jackson序列化器
 *
 * @author gltqe
 * @date 2023/6/14 15:03
 **/
public class CipherDeserializer extends JsonDeserializer<Object> {

    private static ObjectMapper mapper = new ObjectMapper();

    private CipherHandle cipherHandle;

    private Class<?> beanClass;

    public CipherDeserializer(CipherHandle cipherHandle) {
        this.cipherHandle = cipherHandle;
    }


    /**
     * 反序列化
     *
     * @author gltqe
     * @date 2023/6/15 16:20
     **/
    @Override
    public Object deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
        JsonNode rootNode = jsonParser.readValueAsTree();
        Object obj;
        try {
            obj = beanClass.getDeclaredConstructor().newInstance();
            Field[] declaredFields = beanClass.getDeclaredFields();

            for (Field field : declaredFields) {
                field.setAccessible(true);
                String fieldName = field.getName();
                JsonNode node = rootNode.get(fieldName);

                if (node == null || node.isNull()) {
                    continue; // 跳过null字段
                }

                Cipher annotation = field.getAnnotation(Cipher.class);
                Object fieldValue;

                if (annotation != null) {
                    // 处理需要解密的字段
                    String encryptedValue = node.asText();
                    Object decryptedValue = cipherHandle.decryptHandle(annotation, encryptedValue);
                    fieldValue = convertValue(decryptedValue, field.getType(), ctxt);
                } else {
                    // 处理普通字段
                    fieldValue = convertValue(node, field.getType(), ctxt);
                }

                field.set(obj, fieldValue);
            }
        } catch (Exception e) {
            throw new IOException("反序列化失败: " + e.getMessage(), e);
        }
        return obj;
    }

    private Object convertValue(Object value, Class<?> targetType, DeserializationContext ctxt) throws IOException {
        if (value == null) {
            return null;
        }

        // 如果是JsonNode，转换为目标类型
        if (value instanceof JsonNode) {
            JsonNode node = (JsonNode) value;
            try {
                JsonParser parser = node.traverse();
                parser.nextToken(); // 必须调用
                return ctxt.readValue(parser, targetType);
            } catch (IOException e) {
                throw new IOException("无法转换字段值到类型 " + targetType.getName(), e);
            }
        }

        // 如果是字符串且目标类型不是字符串，尝试转换
        if (value instanceof String && !targetType.equals(String.class)) {
            String strValue = (String) value;
            try {
                if (targetType == Integer.class || targetType == int.class) {
                    return Integer.parseInt(strValue);
                } else if (targetType == Long.class || targetType == long.class) {
                    return Long.parseLong(strValue);
                } else if (targetType == Boolean.class || targetType == boolean.class) {
                    return Boolean.parseBoolean(strValue);
                }
                // 添加其他基本类型的转换...
            } catch (NumberFormatException e) {
                throw new IOException("无法将值 '" + strValue + "' 转换为 " + targetType.getName(), e);
            }
        }

        // 如果已经是目标类型或可以自动转换
        if (targetType.isInstance(value)) {
            return value;
        }

        throw new IOException("无法将 " + value.getClass().getName() + " 转换为 " + targetType.getName());
    }

    /**
     * 获取加解密处理器
     *
     * @return: org.gltqe.cipher.CipherHandle
     * @author gltqe
     * @date 2023/6/16 9:31
     **/
    public CipherHandle getCipherHandle() {
        return cipherHandle;
    }

    /**
     * 设置反序列化类
     *
     * @param beanClass
     * @author gltqe
     * @date 2023/6/16 14:53
     **/
    public void setBeanClass(Class<?> beanClass) {
        this.beanClass = beanClass;
    }
}
